/* ====================================================================
 * (#)Header: QueryBuilderJpa.java
 * (#)Revision: 
 * (#)Date Created: 2009-03-31
 * (#)Created By: Karol Wozniak
 * ====================================================================
 *
 * Copyright (c) 2007 karolak .  All rights reserved.
 *
 * ====================================================================
 * 
 * The software application represented here is the sole property of 
 * karolak. Its unauthorized utilization is expressly prohibited.
 * 
 * ====================================================================
 */
package com.karolak.dao.jpa.query;

import java.util.Map;
import java.util.Set;

import javax.persistence.Query;

import com.karolak.query.Criteria;
import com.karolak.query.Criterias;

/**
 * <code>QueryBuilderJpa</code> is ....
 * 
 * @author <a href="mailto:kwozniak@hotmail.com">Karol Wozniak</a>
 */
public class QueryBuilderJpa {

	private static QueryBuilderJpa instance;
	private final String entityAlias = "e";

	static {
		instance = new QueryBuilderJpa();
	}

	public static QueryBuilderJpa getInstance() {
		return instance;
	}

	private QueryBuilderJpa() {
	}

	// === set parameters === //
	public Query setNamedParameters(Query query, Map<String, Object> paramMap) {
		if (paramMap == null || paramMap.isEmpty()) {
			return query;
		}
		Set<Map.Entry<String, Object>> entrySet = paramMap.entrySet();
		for (Map.Entry<String, Object> entry : entrySet) {
			query.setParameter(entry.getKey(), entry.getValue());
		}
		return query;
	}

	public Query setNamedParameters(Query query, Criterias criterias) {

		if (criterias == null || criterias.getEntries() == null || criterias.getEntries().isEmpty()) {
			return query;
		}
		for (Criteria criteria : criterias.getEntries()) {
			if (criteria == null) {
				continue;
			}
			query.setParameter(criteria.getPropertyName(), criteria.getValue());
		}
		return query;
	}

	// === selects === //
	public <T> String createSelectClause(Class<T> clazz) {
		StringBuilder builder = new StringBuilder();
		builder.append("select ").append(entityAlias).append(" from ").append(clazz.getName()).append(" ").append(entityAlias);
		return builder.toString();
	}

	public <T> String createSelectClause(Class<T> clazz, Criterias criterias) {
		StringBuilder builder = new StringBuilder();
		builder.append(createSelectClause(clazz));
		builder.append(createWhereClause(criterias));
		if (criterias != null && criterias.getOrderBy() != null && !criterias.getOrderBy().isEmpty()) {
			builder.append(createOrderByClause(criterias));
		}
		return builder.toString();
	}

	// === count selects === //
	public <T> String createSelectCountClause(Class<T> clazz) {
		StringBuilder builder = new StringBuilder();
		builder.append("select count(").append(entityAlias).append(") from ").append(clazz.getName()).append(" ").append(entityAlias).append(" ");
		return builder.toString();
	}

	public <T> String createSelectCountClause(Class<T> clazz, Criterias criterias) {
		StringBuilder builder = new StringBuilder();
		builder.append(createSelectCountClause(clazz));
		builder.append(createWhereClause(criterias));
		return builder.toString();
	}

	// === where clause === //
	protected String createWhereClause(Criterias criterias) {
		if (criterias == null || criterias.getEntries() == null || criterias.getEntries().isEmpty()) {
			return "";
		}
		StringBuilder builder = new StringBuilder();
		for (int i = 0; i < criterias.getEntries().size(); i++) {
			Criteria criteria = criterias.getEntries().get(i);
			if (criteria == null) {
				continue;
			}
			if (i == 0) {
				builder.append(" where ");
			} else {
				builder.append(" ").append(criteria.getLogicalOperator()).append(" ");
			}
			builder.append(entityAlias).append(".").append(criteria.getPropertyName()).append(" ");
			builder.append(criteria.getEqualityOperator()).append(" ");

			if (criteria.getEqualityOperator().toLowerCase().contains("in")) {
				builder.append("(").append(":").append(criteria.getPropertyName()).append(")");
			} else {
				builder.append(":").append(criteria.getPropertyName());
			}
		}
		return builder.toString();
	}

	// === order by clause === //
	protected String createOrderByClause(Criterias criterias) {
		if (criterias == null || criterias.getOrderBy() == null || criterias.getOrderBy().isEmpty()) {
			return "";
		}
		StringBuilder builder = new StringBuilder();
		builder.append(" order by ");
		boolean first = true;
		for (Map.Entry<String, String> entry : criterias.getOrderBy().entrySet()) {
			if (!first) {
				builder.append(", ");
			}
			String propertyName = entry.getKey();
			String sortOrder = entry.getValue();
			builder.append(entityAlias).append(".").append(propertyName).append(" ");
			if (sortOrder != null) {
				builder.append(sortOrder);
			}
			first = false;
		}

		return builder.toString();
	}
}